//*************************************************************************************
/** \file task_user.cpp
 *    This file contains a task class for running a user interface for the motor
 *    controller demonstration. It has a single-state task which just reads the
 *    serial port to see if the user typed anything, and acts if s/he has done so. 
 *
 *  Revisions:
 *    \li 02-06-2008 JRR Original file
 *    \li 05-15-2008 JRR Modified to work with two motor drivers rather than one
 *    \li 03-08-2009 JRR Added code to test A/D converter
 *    \li 01-19-2011 JRR Updated calls to newer version of stl_task constructor
 *
 *  License:
 *    This file released under the Lesser GNU Public License, version 2. This program
 *    is intended for educational use only, but it is not limited thereto. 
 */
//*************************************************************************************


#include <stdlib.h>
#include <avr/io.h>
#include "rs232int.h"
#include "stl_timer.h"
#include "stl_task.h"
#include "global_debug.h"
#include "avr_adc.h"
#include "motor405.h"
#include "task_motor.h"
#include "task_user.h"


//-------------------------------------------------------------------------------------
/** This constructor creates a user interface task object. It checks if the user has
 *  typed a meaningful command at the serial port and if so tells the motor controller
 *  what to do. 
 *  @param a_timer   A reference to the real-time measuring timer for tasks
 *  @param t_stamp   A timestamp which contains the time between runs of this task
 *  @param p_mo_task A pointer to a motor control task to be ordered around
 *  @param p_timer   A pointer to the main real-time clock object in use
 *  @param p_a_to_d  A pointer to the A/D converter which measures voltages
 *  @param p_ser	 A pointer to a serial device for sending and receiving messages
 */

task_user::task_user (task_timer& a_timer, time_stamp& t_stamp, task_motor* p_mo_task, 
					  avr_adc* p_a_to_d, base_text_serial* p_ser)
	: stl_task (a_timer, t_stamp)
{
	p_motor_task = p_mo_task;				// Save pointers to other objects
	p_a2d = p_a_to_d;
	p_serial_dev = p_ser;

	// Say hello
	GLOB_DEBUG ("User interface task constructor" << endl);
	GLOB_DEBUG ("  G = go, S = stop, R = reverse, 0-7 = A/D reading" 
				<< endl);
}


//-------------------------------------------------------------------------------------
/** This is the function which runs when it is called by the task scheduler. It causes
 *  the motor to move back and forth, having several states to cause such motion. 
 *  @param state The state of the task when this run method begins running
 *  @return The state to which the task will transition, or STL_NO_TRANSITION if no
 *	  transition is called for at this time
 */

char task_user::run (char state)
{
	// Create temporary storage for an A/D channel, if used
	unsigned char channel;

	// There's no switch statement because this task only does one thing all the time:
	// check for a character, and if it's a G or S, tell the motor task what to do
	if (p_serial_dev->check_for_char ())
	{
		char input_char = p_serial_dev->getchar ();
		switch (input_char)
		{
			// Pressing the G key makes the motor begin going
			case ('G'):
			case ('g'):
				///// Make the motor begin going
				p_motor_task->go ();
				break;

			// Pressing the S key makes the motor stop moving
			case ('S'):
			case ('s'):
				///// Make the motor stop
				p_motor_task->stop ();
				break;

			// Pressing R reverses the motion
			case ('R'):
			case ('r'):
				p_motor_task->reverse ();
				GLOB_DEBUG ("Reversing" << endl);
				break;

			// Pressing the T key gives a time check
// 			case ('T'):
// 			case ('t'):
// 				GLOB_DEBUG ("Time: " << p_time_clock->get_time_now () << endl);
// 				break;

			// Pressing a number 0 - 7 gives an A/D reading. Because the AVR sometimes
			// gives bogus readings when switching channels, we'll take the reading 
			// twice to ensure the second one is good
			case ('0'):
			case ('1'):
			case ('2'):
			case ('3'):
			case ('4'):
			case ('5'):
			case ('6'):
			case ('7'):
				channel = input_char - '0';
				p_a2d->read_once (channel);
				GLOB_DEBUG ("A/D ch. " << channel << " reads " 
							<< p_a2d->read_once (channel) << endl);
				break;
	
			// If the user types anything else, just ignore it
			default:
				*p_serial_dev << ascii << input_char << numeric << "?" << endl;
				break;
		}
	}

	// If we get here, no transition is called for
	return (STL_NO_TRANSITION);
}

